#include "ccm4201s.h"
#include "uapi_usb.h"
#include "common.h"
#include <string.h>
#include <stdlib.h>


uint8_t g_ccm4201s_disable_bootloader_bin[CCM4201S_DISABLE_BOOTLOADER_BIN_LEN] = {
    0x2d, 0xe9, 0xf0, 0x41, 0x90, 0xb0, 0x32, 0x48, 0x02, 0x90, 0x32, 0x48, 0x03, 0x90, 0x00, 0x14,
    0x31, 0x49, 0x32, 0x4c, 0x04, 0x90, 0xcd, 0xe9, 0x05, 0x01, 0x21, 0x68, 0x07, 0x91, 0x30, 0x49,
    0x08, 0x91, 0x07, 0x99, 0xb1, 0xf1, 0x10, 0x2f, 0x02, 0xd2, 0x4f, 0xf0, 0x11, 0x30, 0x04, 0xe0,
    0xb1, 0xf1, 0x81, 0x5f, 0x03, 0xd3, 0x4f, 0xf0, 0x99, 0x30, 0x20, 0x60, 0x31, 0xe0, 0x09, 0x05,
    0x02, 0xd0, 0x4f, 0xf0, 0xaa, 0x30, 0xf8, 0xe7, 0x4f, 0xf0, 0x80, 0x58, 0x0b, 0x90, 0x0c, 0x90,
    0x44, 0xf6, 0x19, 0x27, 0x42, 0xf6, 0x61, 0x71, 0x42, 0xf6, 0x05, 0x76, 0x45, 0x46, 0x40, 0x46,
    0x88, 0x47, 0x07, 0xaa, 0x01, 0x21, 0x1f, 0x48, 0xb0, 0x47, 0x02, 0xaa, 0x05, 0x21, 0x1e, 0x48,
    0xb0, 0x47, 0x28, 0x46, 0xb8, 0x47, 0xd5, 0xf8, 0x60, 0x01, 0x09, 0x90, 0xd5, 0xf8, 0x64, 0x01,
    0x0a, 0x90, 0xd5, 0xf8, 0x70, 0x01, 0x0d, 0x90, 0x28, 0x6a, 0x0e, 0x90, 0x17, 0x4d, 0x00, 0x20,
    0x02, 0xa9, 0x09, 0xaa, 0x51, 0xf8, 0x20, 0xc0, 0x52, 0xf8, 0x20, 0x30, 0x63, 0x45, 0x04, 0xd0,
    0x25, 0x60, 0x10, 0xb0, 0x00, 0x20, 0xbd, 0xe8, 0xf0, 0x81, 0x40, 0x1c, 0x06, 0x28, 0xf1, 0xd3,
    0x01, 0xf1, 0x18, 0x02, 0x01, 0x21, 0x40, 0x46, 0xb0, 0x47, 0x40, 0x46, 0xb8, 0x47, 0xd8, 0xf8,
    0x00, 0x00, 0x08, 0x99, 0x0f, 0x90, 0x81, 0x42, 0xea, 0xd1, 0x09, 0x48, 0xb5, 0xe7, 0x00, 0x00,
    0x66, 0x99, 0x38, 0xc0, 0xeb, 0x0c, 0xff, 0xff, 0x02, 0x02, 0x21, 0x04, 0x00, 0x30, 0x00, 0x20,
    0x21, 0x37, 0xec, 0x3a, 0x20, 0x00, 0x00, 0x10, 0x60, 0x01, 0x00, 0x10, 0x78, 0x56, 0x34, 0x12,
    0xaa, 0x55, 0xaa, 0x55
};

static int ccm4201s_send_mass_storage_command(uapi_usb_handle *handle, uint8_t lun,
    uint8_t *cdb, uint8_t direction, uint32_t transfer_length, uint32_t *ret_tag)
{
    static uint32_t tag = 1;
    uint8_t cdb_len = CCM4201S_CMD_LEN; //默认长度为16，ccm4201的命令长度
    int i, r, size;
    int32_t ret = 0;
    struct command_block_wrapper cbw;
    uapi_usb_cmd cmd = {0};

    if (cdb == NULL) {
        return -1;
    }

    if (handle->endpoint_out & LIBUSB_ENDPOINT_IN) {
        OFP_LOGE("ccm4201s_send_mass_storage_command: cannot send command on IN endpoint\n");
        return -1;
    }

    memset(&cbw, 0, sizeof(cbw));
    cbw.dCBWSignature[0] = 'U';
    cbw.dCBWSignature[1] = 'S';
    cbw.dCBWSignature[2] = 'B';
    cbw.dCBWSignature[3] = 'C';
    *ret_tag = tag;
    cbw.dCBWTag = tag++;
    cbw.dCBWDataTransferLength = transfer_length;
    cbw.bmCBWFlags = direction;
    cbw.bCBWLUN = lun;
    // Subclass is 1 or 6 => cdb_len
    cbw.bCBWCBLength = cdb_len;
    memcpy(cbw.CBWCB, cdb, cdb_len);

    cmd.buf = ((uint8_t *)(&cbw));
    cmd.need_write_len = 31; //需要注意，不能使用sizeof,sizeof有系统对齐了多余字节
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;

    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_send_mass_storage_command--->uapi_usb_bulk_transfer \n");
        return ret;
    }

    OFP_LOGD("sent %d CDB bytes\n", cdb_len);
    return 0;
}


static int ccm4201s_get_mass_storage_status(uapi_usb_handle *handle, uint32_t expected_tag)
{
    int i, r, size, ret;
    struct command_status_wrapper csw;

    uapi_usb_cmd cmd = {0};
    cmd.buf = ((uint8_t *)(&csw));
    cmd.need_read_len = 13; //注意size大小不能采用sizeof，sizeof有对齐导致多余直接
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;

    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_send_mass_storage_command--->uapi_usb_bulk_transfer \n");
        return ret;
    }

    if ((csw.dCSWSignature[0] != 'U') && (csw.dCSWSignature[1] != 'S')
        && (csw.dCSWSignature[2] != 'B') && (csw.dCSWSignature[3] != 'S')) {
        OFP_LOGE("ccm4201s_send_mass_storage_command: tags USBS error\n");
        return -1;
    }

    if (csw.dCSWTag != expected_tag) {
        OFP_LOGE("ccm4201s_get_mass_storage_status: mismatched tags (expected %08X, received %08X)\n",
            expected_tag, csw.dCSWTag);
        return -1;
    }
    // For this test, we ignore the dCSWSignature check for validity...
    OFP_LOGI("Mass Storage Status: %02X (%s)\n", csw.bCSWStatus, csw.bCSWStatus?"FAILED":"Success");

    if (csw.bCSWStatus) {
        if (csw.bCSWStatus == 1)
            return -2;  // request Get Sense
        else
            return -1;
    }


    return 0;
}

static void ccm4201s_get_mass_storage_sense(uapi_usb_handle *handle)
{
    uint8_t cdb[CCM4201S_CMD_LEN];  // SCSI Command Descriptor Block
    uint8_t sense[CCM4201S_REQUEST_SENSE_LENGTH];
    uint32_t expected_tag;
    int ret;
    uint8_t lun = 0; //默认值，芯片固定
    uapi_usb_cmd cmd = {0};

    memset(sense, 0, sizeof(sense));
    memset(cdb, 0, sizeof(cdb));
    cdb[0] = 0x03;  // Request Sense
    cdb[4] = CCM4201S_REQUEST_SENSE_LENGTH;

    ccm4201s_send_mass_storage_command(handle, lun, cdb, UAPI_ENDPOINT_IN, CCM4201S_REQUEST_SENSE_LENGTH, &expected_tag);

    cmd.buf = sense;
    cmd.need_read_len = CCM4201S_REQUEST_SENSE_LENGTH;
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;
    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("get_mass_storage_sense--->uapi_usb_bulk_transfer");
        return;
    }


    if ((sense[0] != 0x70) && (sense[0] != 0x71)) {
        OFP_LOGE("   ERROR No sense data\n");
    } else {
        OFP_LOGE("   ERROR Sense: %02X %02X %02X\n", sense[2]&0x0F, sense[12], sense[13]);
    }
    ccm4201s_get_mass_storage_status(handle, expected_tag);
}

static int32_t ccm4201s_get_boot_version(uapi_usb_handle *handle)
{
    uint32_t expected_tag = 0;
    uint8_t version_len = CCM4201S_BOOT_VERSION_LEN;
    uint8_t boot_version[CCM4201S_BOOT_VERSION_LEN + 1] = {0};
    uint8_t lun = 0; //默认值，芯片固定
    int32_t ret;

    uint8_t boot_version_header[CCM4201S_BOOT_VERSION_LEN] = "CC Bootloader Version";
    uapi_usb_cmd cmd = {0};
    uint8_t get_boot_version_cmd[CCM4201S_CMD_LEN] = {0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
    OFP_LOGD("ccm4201s_get_boot_version======================>enter\n");


    ret = ccm4201s_send_mass_storage_command(handle, lun, get_boot_version_cmd, UAPI_ENDPOINT_IN, version_len, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_get_boot_version--->ccm4201s_send_mass_storage_command error\n");
        return -1;
    }

    cmd.buf = boot_version;
    cmd.need_read_len = version_len;
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;
    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_get_boot_version--->uapi_usb_bulk_transfer  error exit\n");
        return ret;
    }

    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("   ccm4201s_get_boot_version--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    OFP_LOGD("get boot version:  %s\n", boot_version);
    if (memcmp(boot_version, boot_version_header, strlen(boot_version_header)) != 0) {
        return -1;
    }

    OFP_LOGI("boot version:  %s\n", boot_version);

    OFP_LOGD("ccm4201s_get_boot_version======================>exit\n");

    return 0;
}

static int32_t ccm4201s_write_first_memory_package(uapi_usb_handle *handle)
{
    uint8_t write_first_memory_package_cmd[CCM4201S_CMD_LEN] = {0xdc, 0xbc, 0x04, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int32_t ret = 0;
    uapi_usb_cmd cmd = {0};
    uint8_t write_data_buf[32] = {0x66, 0x99, 0x38, 0xc0, 0xeb, 0x0c, 0x06, 0x05, 0x35, 0x31, 0x32, 0x20, 0x52, 0xd8, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00};

    uint8_t write_data[CCM4201S_MEMORY_PAGE_LEN] = {0};
    memset(write_data, 0, CCM4201S_MEMORY_PAGE_LEN);
    memcpy(write_data, write_data_buf, 32);

    OFP_LOGD("ccm4201s_write_first_memory_package======================>enter\n");
    ret = ccm4201s_send_mass_storage_command(handle, lun, write_first_memory_package_cmd,
        UAPI_ENDPOINT_OUT, CCM4201S_MEMORY_PAGE_LEN, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_first_memory_package--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }


    cmd.buf = write_data;
    cmd.need_write_len = CCM4201S_MEMORY_PAGE_LEN;
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;
    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_first_memory_package--->uapi_usb_bulk_transfer exit \n");
        return ret;
    }

    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_get_boot_version--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    OFP_LOGD("ccm4201s_write_first_memory_package======================>exit\n");

    return 0;
}

static int32_t ccm4201s_page_erase(uapi_usb_handle *handle, uint32_t flash_addr, uint32_t page_num)
{
    uint8_t page_erase_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int ret;

    memcpy(page_erase_cmd + 1, &flash_addr, 4);
    memcpy(page_erase_cmd + 1 + 4, &page_num, 4);

    OFP_LOGD("ccm4201s_write_first_memory_package======================>enter\n");
    ret = ccm4201s_send_mass_storage_command(handle, lun, page_erase_cmd,
        UAPI_ENDPOINT_OUT, 0, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_first_memory_package--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }


    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_get_boot_version--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    OFP_LOGD("ccm4201s_write_first_memory_package======================>exit\n");

    return 0;
}


static int32_t ccm4201s_config_enable_verify(uapi_usb_handle *handle, uint32_t addr_para2,
    uint32_t check_len_para3, uint32_t para4, uint8_t para1, uint32_t verify_type)
{
    //uint8 buffer[64];
    uint8_t config_enable_verify_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int32_t ret;
    uint8_t read_data[CCM4201S_MEMORY_PAGE_LEN] = {0};
    uapi_usb_cmd cmd = {0};

    memcpy(config_enable_verify_cmd + 1, &addr_para2, 4);
    memcpy(config_enable_verify_cmd + 1 + 4, &check_len_para3, 4);

    memcpy(config_enable_verify_cmd + 1 + 4 + 4, &para4, 4);

    config_enable_verify_cmd[14] = para1;

    OFP_LOGD("ccm4201s_config_enable_verify======================>enter\n");

    ret = ccm4201s_send_mass_storage_command(handle, lun, config_enable_verify_cmd,
        UAPI_ENDPOINT_IN, CCM4201S_MEMORY_PAGE_LEN, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable_verify--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }
    cmd.buf = read_data;
    cmd.need_read_len = CCM4201S_MEMORY_PAGE_LEN;
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;
    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable_verify--->uapi_usb_bulk_transfer");
        return ret;
    }
    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable_verify--->ccm4201s_get_mass_storage_status error exit\n");
        return -1;
    }

    if (verify_type == CCM4201S_BOOTLOADER_VERIFY_TYPE) {
        if ((read_data[0] != 0xaa) || (read_data[1] != 0x55) || (read_data[2] != 0xaa) || (read_data[3] != 0x55)) {
            OFP_LOGE("0x%02x 0x%02x 0x%02x 0x%02x \n", read_data[0], read_data[1], read_data[2], read_data[3]);
            OFP_LOGE("ccm4201s_config_enable_verify--->bootloader verify  error exit\n");
            return -1;
        }
    }

    OFP_LOGD("ccm4201s_config_enable_verify======================>exit\n");

    return 0;
}

static int32_t ccm4201s_write_sram_memory(uapi_usb_handle *handle, uint32_t addr, uint8_t *data, uint32_t len)
{
    uint32_t write_memory_data_len = 0;
    uint8_t write_memory_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int32_t ret;
    uapi_usb_cmd cmd = {0};
    uint8_t *write_memory_data = NULL;

    if ((len % CCM4201S_MEMORY_PAGE_LEN) != 0) {
        write_memory_data_len = ((len / CCM4201S_MEMORY_PAGE_LEN) + 1) * CCM4201S_MEMORY_PAGE_LEN;
    } else {
        write_memory_data_len = len;
    }

    memcpy(write_memory_cmd + 1, &addr, 4);
    memcpy(write_memory_cmd + 1 + 4, &len, 4);
    OFP_LOGD("ccm4201s_write_sram_memory======================>enter\n");

    ret = ccm4201s_send_mass_storage_command(handle, lun, write_memory_cmd,
        UAPI_ENDPOINT_OUT, write_memory_data_len, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_memory--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    write_memory_data = (uint8_t *)calloc(1, write_memory_data_len * sizeof(uint8_t));

    memcpy(write_memory_data, data, len);

    cmd.buf = write_memory_data;
    cmd.need_write_len = write_memory_data_len;
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;
    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_memory--->uapi_usb_bulk_transfer");
        free(write_memory_data);
        return ret;
    }

    free(write_memory_data);

    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_memory--->ccm4201s_get_mass_storage_status error exit\n");
        return -1;
    }
    OFP_LOGD("ccm4201s_write_sram_memory======================>exit\n");

    return 0;
}


static int32_t ccm4201s_bulk_program_data(uapi_usb_handle *handle, uint32_t eflash_addr, uint32_t data_len, uint32_t sram_addr)
{
    uint8_t bulk_program_data_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int32_t ret;

    OFP_LOGD("ccm4201s_bulk_program_data======================>enter\n");



    memcpy(bulk_program_data_cmd + 1, &eflash_addr, 4);
    memcpy(bulk_program_data_cmd + 1 + 4, &data_len, 4);
    memcpy(bulk_program_data_cmd + 1 + 4 + 4, &sram_addr, 4);

    ret = ccm4201s_send_mass_storage_command(handle, lun, bulk_program_data_cmd,
        UAPI_ENDPOINT_OUT, 0u, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_bulk_program_data--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_bulk_program_data--->ccm4201s_get_mass_storage_status error exit\n");
        return -1;
    }
    OFP_LOGD("ccm4201s_bulk_program_data======================>exit\n");

    return 0;
}


static int32_t ccm4201s_sha_verify(uapi_usb_handle *handle, uint32_t eflash_addr, uint32_t data_len,
    uint8_t* sha1_result, uint8_t sha1_len)
{
    uint8_t sha_verify_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int size, ret;
    uint8_t read_data[CCM4201S_MEMORY_PAGE_LEN] = {0};
    uapi_usb_cmd cmd = {0};
    uint8_t *write_memory_data = NULL;


    memcpy(sha_verify_cmd + 1, &eflash_addr, 4);
    memcpy(sha_verify_cmd + 1 + 4, &data_len, 4);
    sha_verify_cmd[14] = 0x20;
    OFP_LOGD("ccm4201s_sha_verify======================>enter\n");

    ret = ccm4201s_send_mass_storage_command(handle, lun, sha_verify_cmd,
        UAPI_ENDPOINT_IN, sha1_len, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_sha_verify--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    cmd.buf = read_data;
    cmd.need_read_len = sha1_len;
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;
    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_sha_verify--->uapi_usb_bulk_transfer");
        return ret;
    }

    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_sha_verify--->ccm4201s_get_mass_storage_status error exit\n");
        return -1;
    }

    memcpy(sha1_result, cmd.buf, sha1_len);
    OFP_LOGD("ccm4201s_sha_verify======================>exit\n");

    return 0;
}

static int32_t ccm4201s_write_last_memory_package(uapi_usb_handle *handle)
{
    uint8_t write_last_memory_package_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x30, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int size, ret;
    uapi_usb_cmd cmd = {0};
    uint8_t write_data_buff[4] ={0x00, 0x10, 0x00, 0x10};


    uint8_t write_data[CCM4201S_MEMORY_PAGE_LEN] = {0};
    memset(write_data,  0x00, CCM4201S_MEMORY_PAGE_LEN);
    memcpy(write_data, write_data_buff, 4);



    OFP_LOGD("ccm4201s_write_last_memory_package======================>enter\n");
    ret = ccm4201s_send_mass_storage_command(handle, lun, write_last_memory_package_cmd,
        UAPI_ENDPOINT_OUT, CCM4201S_MEMORY_PAGE_LEN, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_last_memory_package--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }


    cmd.buf = write_data;
    cmd.need_write_len = CCM4201S_MEMORY_PAGE_LEN;
    cmd.timeout = CCM4201S_BOOT_TRANSFER_TIMEOUT;
    ret = uapi_usb_bulk_transfer(handle, &cmd);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_last_memory_package--->uapi_usb_bulk_transfer exit \n");
        return ret;
    }

    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_last_memory_package--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    OFP_LOGD("ccm4201s_write_last_memory_package======================>exit\n");

    return 0;
}

static int32_t ccm4201s_config_enable(uapi_usb_handle *handle, uint32_t sram_addr)
{
    uint8_t config_enable_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int size, ret;
    uapi_usb_cmd cmd = {0};

    OFP_LOGD("ccm4201s_config_enable======================>enter\n");
    memcpy(config_enable_cmd + 1, &sram_addr, 4);

    ret = ccm4201s_send_mass_storage_command(handle, lun, config_enable_cmd,
        UAPI_ENDPOINT_OUT, 0, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    OFP_LOGD("ccm4201s_config_enable======================>exit\n");

    return 0;
}

static int32_t ccm4201s_soft_reset(uapi_usb_handle *handle, uint8_t para1)
{
    uint8_t soft_reset_cmd[CCM4201S_CMD_LEN] = {0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00};
    uint8_t lun = 0;
    uint32_t expected_tag;
    int size, ret;
    uapi_usb_cmd cmd = {0};

    OFP_LOGD("ccm4201s_soft_reset======================>enter\n");
    soft_reset_cmd[14] = para1;

    ret = ccm4201s_send_mass_storage_command(handle, lun, soft_reset_cmd,
        UAPI_ENDPOINT_OUT, 0, &expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_soft_reset--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }

    //重启后没有报文回复
    /*ret = ccm4201s_get_mass_storage_status(handle, expected_tag);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_write_last_memory_package--->ccm4201s_send_mass_storage_command error exit\n");
        return -1;
    }*/

    OFP_LOGD("ccm4201s_soft_reset======================>exit\n");

    return 0;
}


static int32_t ccm4201s_config_enable_verify_four_times(uapi_usb_handle *handle)
{
    int32_t ret;

    OFP_LOGD("ccm4201s_config_enable_verify_four_times======================>enter\n");

    ret = ccm4201s_config_enable_verify(handle, 0x40003824,0x04, 0x00, 0x01, CCM4201S_OTHER_VERIFY_TYPE);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable_verify 0x40003824,0x04, 0x00, 0x01 error exit\n");
        return -1;
    }

    ret = ccm4201s_config_enable_verify(handle, 0x40003824,0x04, 0x00, 0x02, CCM4201S_OTHER_VERIFY_TYPE);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable_verify 0x40003824,0x04, 0x00, 0x02 error exit\n");
        return -2;
    }

    ret = ccm4201s_config_enable_verify(handle, 0x4000382c,0x04, 0x00, 0x01, CCM4201S_OTHER_VERIFY_TYPE);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable_verify 0x4000382c,0x04, 0x00, 0x01 error exit\n");
        return -3;
    }

    ret = ccm4201s_config_enable_verify(handle, 0x4000382c,0x04, 0x01f00000, 0x02, CCM4201S_OTHER_VERIFY_TYPE);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_config_enable_verify usb_handle, 0x4000382c,0x04, 0x01f0000, 0x02 error exit\n");
        return -4;
    }
    OFP_LOGD("ccm4201s_config_enable_verify_four_times======================>exit\n");

    return 0;

}

static int32_t ccm4201s_write_firmware_to_flash(uapi_usb_handle *handle, ofp_upgrade_firmware *firmware)
{
    int32_t ret;
    uint32_t flash_addr = CCM4201S_FLASH_BASE_ADDR;
    uint32_t data_index = firmware->firmware_len / CCM4201S_MEMORY_WRITE_LEN_MAX;
    int32_t i = 0;
    uint32_t firmware_data_left = 0;

    OFP_LOGD("ccm4201s_write_firmware_to_flash======================>enter\n");

    for (i = 0; i < data_index; i++) {
        ret = ccm4201s_write_sram_memory(handle, CCM4201S_SRAM_BASE_ADDR,
            firmware->firmware_data + i * CCM4201S_MEMORY_WRITE_LEN_MAX, CCM4201S_MEMORY_WRITE_LEN_MAX);
        if (ret < 0) {
            OFP_LOGE("ccm4201s_write_firmware_to_flash--->ccm4201s_write_sram_memory error exit\n");
            return -1;
        }
        ret = ccm4201s_bulk_program_data(handle, flash_addr + i * CCM4201S_MEMORY_WRITE_LEN_MAX,
            CCM4201S_MEMORY_WRITE_LEN_MAX, CCM4201S_SRAM_BASE_ADDR);
        if (ret < 0) {
            OFP_LOGE("ccm4201s_write_firmware_to_flash--->ccm4201s_bulk_program_data error exit\n");
            return -2;
        }
    }


    firmware_data_left = (firmware->firmware_len % CCM4201S_MEMORY_WRITE_LEN_MAX);

    if (firmware_data_left != 0) {
        ret = ccm4201s_write_sram_memory(handle, CCM4201S_SRAM_BASE_ADDR,
            firmware->firmware_data + data_index * CCM4201S_MEMORY_WRITE_LEN_MAX, firmware_data_left);
        if (ret < 0) {
            OFP_LOGE("ccm4201s_write_firmware_to_flash--->ccm4201s_write_sram_memory error exit\n");
            return -1;
        }

        ret = ccm4201s_bulk_program_data(handle, flash_addr + data_index * CCM4201S_MEMORY_WRITE_LEN_MAX,
            firmware_data_left, CCM4201S_SRAM_BASE_ADDR);
        if (ret < 0) {
            OFP_LOGE("ccm4201s_write_firmware_to_flash--->ccm4201s_bulk_program_data error exit\n");
            return -2;
        }

    }
    OFP_LOGD("ccm4201s_write_firmware_to_flash======================>exit\n");


    return 0;
}

int32_t ccm4201s_usb_upgrade(void *boot_usb_handle, void *upgrade_firmware)
{
    uapi_usb_handle * usb_handle = NULL;
    ofp_upgrade_firmware *firmware = NULL;
    int32_t ret;
    uint32_t flash_page_num = 0;
    uint8_t sha1_result[CCM4201S_SHA1_VERIFY_RESULT_LEN] = {0};
    uint8_t i = 0;
    OFP_LOGD("ccm4201s_usb_upgrade======================>enter\n");

    if ((boot_usb_handle == NULL) || (upgrade_firmware == NULL)) {
        OFP_LOGE("ccm4201s_usb_upgrade--->error param error exit\n");
        return -1;
    }

    usb_handle = (uapi_usb_handle *)boot_usb_handle;
    firmware = (ofp_upgrade_firmware *)upgrade_firmware;

    if (((firmware->firmware_len) % 4) != 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->firmware len:%d  error exit\n", firmware->firmware_len);
        return -1;
    }

    if (usb_handle->handle == NULL) {
        OFP_LOGE("ccm4201s_usb_upgrade--->usb boot handle NULL \n");
        return -1;
    }

    ret = ccm4201s_get_boot_version(usb_handle);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_get_boot_version error exit\n");
        return -2;
    }
    ret = ccm4201s_write_first_memory_package(usb_handle);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_write_first_memory_package error exit\n");
        return -3;
    }


    if (((firmware->firmware_len) % CCM4201S_EFLASH_PAGE_LEN) != 0) {
        flash_page_num = ((firmware->firmware_len) / CCM4201S_EFLASH_PAGE_LEN) + 1;
    } else {
        flash_page_num = ((firmware->firmware_len) / CCM4201S_EFLASH_PAGE_LEN);
    }

    ret = ccm4201s_page_erase(usb_handle, CCM4201S_FLASH_BASE_ADDR, flash_page_num);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_page_erase error exit\n");
        return -4;
    }

    ret = ccm4201s_config_enable_verify_four_times(usb_handle);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_config_enable_verify_four_times error exit\n");
        return -5;
    }

    ret = ccm4201s_write_firmware_to_flash(usb_handle, firmware);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_write_firmware_to_flash error exit\n");
        return -6;
    }

    ret = ccm4201s_config_enable_verify(usb_handle, 0x40003824,0x04, 0x00, 0x02, CCM4201S_OTHER_VERIFY_TYPE);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade --->ccm4201s_config_enable_verify 0x40003824,0x04, 0x00, 0x01 error exit\n");
        return -7;
    }

    ret = ccm4201s_sha_verify(usb_handle, CCM4201S_FLASH_BASE_ADDR, firmware->firmware_len,
        sha1_result, CCM4201S_SHA1_VERIFY_RESULT_LEN);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade --->ccm4201s_sha_verify error exit\n");
        return -8;
    }

    OFP_LOGI("ccm4201s_sha_verify sha1_result:");
    for (i = 0; i < CCM4201S_SHA1_VERIFY_RESULT_LEN; i++) {
        printf("0x%02x ", sha1_result[i]);
    }
    printf("\n");

    ret = ccm4201s_write_last_memory_package(usb_handle);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_write_last_memory_package error exit\n");
        return -9;
    }

    ret = ccm4201s_write_sram_memory(usb_handle, CCM4201S_SRAM_BASE_ADDR, \
        g_ccm4201s_disable_bootloader_bin, CCM4201S_DISABLE_BOOTLOADER_BIN_LEN);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_write_sram_memory error exit\n");
        return -10;
    }

    ret = ccm4201s_config_enable(usb_handle, CCM4201S_SRAM_BASE_ADDR);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_config_enable error exit\n");
        return -11;
    }

    ret = ccm4201s_config_enable_verify(usb_handle, 0x20003000,0x04, 0x00, 0x01, CCM4201S_BOOTLOADER_VERIFY_TYPE);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_config_enable_verify 0x20003000,0x04, 0x00, 0x01 error exit\n");
        return -12;
    }

    ret = ccm4201s_soft_reset(usb_handle, 0x00);
    if (ret < 0) {
        OFP_LOGE("ccm4201s_usb_upgrade--->ccm4201s_soft_reset error exit\n");
        return -13;
    }

    OFP_LOGD("ccm4201s_usb_upgrade======================>exit\n");

    return 0;
}
